package com.ant.backstage.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.ant.backstage.facade.ApiReturn;
import com.ant.backstage.facade.code.ApiReturnCode;
import com.ant.backstage.facade.dto.CheckVerifyCodeDTO;
import com.ant.backstage.facade.enums.MailTypeEnum;
import com.ant.backstage.facade.enums.VerificationTypeEnum;
import com.ant.backstage.facade.request.CheckVerifyCodeRequest;
import com.ant.backstage.facade.request.GetVerificationCodeRequest;
import com.ant.backstage.facade.request.MailRequest;
import com.ant.backstage.service.RegisterAndLoginService;
import com.ant.backstage.service.SendMailService;
import com.ant.backstage.service.VerificationICodeService;
import com.ant.backstage.utils.RedisUtil;
import ma.glasnost.orika.MapperFacade;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;


/**
 * @author Administrator
 */
//@Service("verificationService")
@Service
public class VerificationServiceImpl implements VerificationICodeService {

    private static Logger logger = LogManager.getLogger(UserServiceImpl.class);

    @Resource
    RedisUtil redisUtil;

    @Resource
    MapperFacade mapperFacade;

    @Resource
    SendMailService sendMailService;

    @Resource
    RegisterAndLoginService registerAndLoginService;


    @Override
    public ApiReturn getVerificationCode(GetVerificationCodeRequest getRequest) {
        ApiReturn apiReturn = new ApiReturn();
        if (getRequest.getContactType().equals(VerificationTypeEnum.VERIFICATION_PHONE.getCode()) ||
                getRequest.getContactType().equals(VerificationTypeEnum.VERIFICATION_RANDOM.getCode())) {
            apiReturn = this.getVerificationCode(getRequest.getCurrentIp(), getRequest.getUname(), getRequest.getUserContact(), getRequest.getContactType());
            if (apiReturn.getCode().equals(ApiReturnCode.SUCCESSFUL.getCode())) {
                return apiReturn;
            } else {
                logger.error("验证码生成异常");
                return apiReturn;
            }
        }
        if (getRequest.getContactType().equals(VerificationTypeEnum.VERIFICATION_MAIL.getCode())) {
            MailRequest mailRequest = new MailRequest();
            mailRequest.setAcceptList(getRequest.getUserContact());
            mailRequest.setMainTheme("获取验证码");
            mailRequest.setMailType(MailTypeEnum.IMG_SLAVE_MAIL.getCode());
            mailRequest.setTemplateName("img_slave_mail");
            String url = "D:\\idea-develop-project\\Project_All\\backstage_ant\\web\\src\\main\\resources\\static\\img\\img.jpg";
            mailRequest.setImgUrl(url);//验证码模板带图片，图暂时默认
            mailRequest.setUname(getRequest.getUname());
            mailRequest.setCurrentIp(getRequest.getCurrentIp());
            apiReturn = this.sendMail(mailRequest);
        }
        return apiReturn;
    }

    @Override
    public ApiReturn checkVerificationCode(CheckVerifyCodeRequest checkVerifyCodeRequest, HttpServletResponse response) {
        ApiReturn apiReturn = new ApiReturn();
        ApiReturn firewall = flushFirewall(checkVerifyCodeRequest.getCurrentIp(), checkVerifyCodeRequest.getContactType());
        if (!firewall.getCode().equals(ApiReturnCode.SUCCESSFUL.getCode())) {
            return firewall;
        }
        //1.获得请求IP
        String ip = checkVerifyCodeRequest.getCurrentIp();
        //2.拼接key
        String redisKey = ip + "::" + checkVerifyCodeRequest.getContactType() + "::" + checkVerifyCodeRequest.getUname()
                + "::codeVale::" + checkVerifyCodeRequest.getVerifyCode();
        boolean b = redisUtil.hasKey(redisKey);
        if (b) {
            String redisVerifyCode = (String) redisUtil.get(redisKey);
            //3.校验
            if (!redisVerifyCode.equals(checkVerifyCodeRequest.getVerifyCode())) {
                logger.error("验证码校验失败ip={},verifyCode={}", ip, checkVerifyCodeRequest.getVerifyCode());
                apiReturn.setApiReturnCode(ApiReturnCode.VERIFYCODE_LOSE);
            }
            Map<String, String> claims = new HashMap<>();
            claims.put("uname", checkVerifyCodeRequest.getUname());
            if (checkVerifyCodeRequest.getContactType().equals(VerificationTypeEnum.VERIFICATION_RANDOM.getCode())) {
                redisUtil.del(redisKey);
                apiReturn.setApiReturnCode(ApiReturnCode.SUCCESSFUL);
                return apiReturn;
            }
            //生成校验token
            String jwt = registerAndLoginService.generateJwt(claims);
            //存redis
            CheckVerifyCodeDTO dto = mapperFacade.map(checkVerifyCodeRequest, CheckVerifyCodeDTO.class);
            redisUtil.set(jwt, dto, 60 * 30);
            if (checkVerifyCodeRequest.getContactType().equals(VerificationTypeEnum.VERIFICATION_PHONE.getCode())) {
                response.addHeader("SMS", jwt);
            }
            apiReturn.setApiReturnCode(ApiReturnCode.SUCCESSFUL);
        } else {
            logger.error("验证码校验失败ip={},verifyCode={}", ip, checkVerifyCodeRequest.getVerifyCode());
            apiReturn.setApiReturnCode(ApiReturnCode.VERIFYCODE_LOSE);
        }
        return apiReturn;
    }

    @Override
    public ApiReturn sendMail(MailRequest mailRequest) {
        //防刷
        ApiReturn firewall = flushFirewall(mailRequest.getCurrentIp(), VerificationTypeEnum.VERIFICATION_MAIL.getCode());
        if (!firewall.getCode().equals(ApiReturnCode.SUCCESSFUL.getCode())) {
            return firewall;
        }
        Map map = (Map) firewall.getData();
        String rediskeyCode = (String) map.get("rediskey");
        ApiReturn apiReturn = sendMailService.sendMail(mailRequest);
        if (apiReturn.getCode().equals(ApiReturnCode.SUCCESSFUL.getCode())
                && mailRequest.getMailType().equals(MailTypeEnum.IMG_SLAVE_MAIL.getCode())) {
            //是验证码邮件，验证码存缓存
            String mailVerifCode = (String) apiReturn.getData();
            //缓存，有效5分钟
            redisUtil.set(rediskeyCode + "::" + mailRequest.getUname() + "::codeVale::" + mailVerifCode, mailVerifCode, 5 * 60);
            apiReturn.setData(null);
        }
        return apiReturn;
    }


    /**
     * @return
     * @Author zhangyu
     * @Description
     * @Date 15:26 2021/12/28
     * @Param 验证码
     **/
    public ApiReturn getVerificationCode(String IP, String uname, String Phone, String type) {
        ApiReturn apiReturn = new ApiReturn();
        ApiReturn firewall = this.flushFirewall(IP, type);
        if (!firewall.getCode().equals(ApiReturnCode.SUCCESSFUL.getCode())) {
            return firewall;
        }
        Map map = (Map) firewall.getData();
        String rediskeyCode = (String) map.get("rediskey");
        //生成6位验证码
        String verifyCode = String.valueOf(new Random().nextInt(899999) + 100000);
        //缓存，有效5分钟
        redisUtil.set(rediskeyCode + "::" + uname + "::codeVale::" + verifyCode, verifyCode, 5 * 60);
        Map<String, Object> stringObjectHashMap = new HashMap<>();
        stringObjectHashMap.put("verifyCode", verifyCode);
        if (type.equals(VerificationTypeEnum.VERIFICATION_PHONE.getCode())) {
            //TODO 调用手机号发送短信
        }
        if (type.equals(VerificationTypeEnum.VERIFICATION_RANDOM.getCode())) {
            apiReturn.setData(stringObjectHashMap);
        }
        apiReturn.setApiReturnCode(ApiReturnCode.SUCCESSFUL);
        return apiReturn;
    }

    public ApiReturn flushFirewall(String ip, String type) {
        ApiReturn apiReturn = new ApiReturn();
        apiReturn.setCode(ApiReturnCode.SUCCESSFUL.getCode());
        apiReturn.setMsg(ApiReturnCode.SUCCESSFUL.getMessage());
        Map<String, Object> map = new HashMap<>();
        map.put("ip", ip);
        map.put("type", type);
        //根据请求类型 【短信/验证码】拼接rediskey 判断请求次数
        String rediskey = ip + "::" + type;
        map.put("rediskey", rediskey);
        boolean b = redisUtil.hasKey(rediskey);
        if (!b) {
            //第一次访问 10分钟访问100次
            redisUtil.set(rediskey, 1, 60 * 10);
            apiReturn.setData(map);
            return apiReturn;
        }
        int getNum = (int) redisUtil.get(rediskey);
        if (getNum < 60) {
            /**
             * 问题： io.lettuce.core.RedisCommandExecutionException: ERR value is not an integer or out of range
             *写入redis失败
             **/
            boolean set = redisUtil.set(rediskey, getNum + 1, 60 * 10);
            apiReturn.setData(map);
            return apiReturn;
        } else {
            logger.error("操作频繁，请稍后再试！map={}", JSONObject.toJSONString(map));
            apiReturn.setCode(ApiReturnCode.PLEASE_AGAIN_LATER.getCode());
            apiReturn.setMsg(ApiReturnCode.PLEASE_AGAIN_LATER.getMessage());
            return apiReturn;
        }
    }
}
